import datetime
import io
import random
import string
import time
import uuid

from flask_mail import Message
from sqlalchemy import func

from blueprints.forms.UserForm import UserLoginForm, UserRegisterForm, UserMissPasswordForm
from utils.createImgCode import checkCode
from flask import Blueprint, render_template, request, jsonify, session, redirect, url_for, make_response, flash, \
    g
from exts import db, mail
from models import ProductModel, RatingsModel, UserModel
from decorators import login_required
from utils.hashUtils import hashPassword

bp = Blueprint("business", __name__, url_prefix="/")


@bp.route("/")
def views():
    """返回首页前端"""
    return render_template("index.html")


@bp.route("/tmp")
def view_tmp():
    return render_template("tmp.html")


# 登录
@bp.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        form = UserLoginForm(data=request.form)
        if form.validate():
            # 获取用户提交的登录信息
            account = form.account.data
            # 如果身份验证成功，将用户account存储在会话对象中
            session['account'] = account
            # 重定向到首页
            return redirect(url_for("business.views"))
        else:
            # 获取所以错误内容，并储存到flask中，然后在模板中把flask信息展示出来
            for errors in form.errors.values():
                for error in errors:
                    flash(error)
            return render_template("login.html", form=form)
    else:
        form = UserLoginForm()
        # 如果是GET请求，返回登录页面
        return render_template('login.html', form=form)


@bp.route("/login/imageCode", methods=['GET'])
def imageCode():
    # 生成图片和验证码
    image, code = checkCode()
    # 将生成的验证码字符串和当前时间戳保存到用户的会话(session)中
    session['imageCode'] = {'code': code, 'timestamp': time.time()}
    # 创建一个字节流对象，将验证码图片保存为PNG格式，并将光标移至开头
    img_io = io.BytesIO()
    image.save(img_io, 'PNG')
    img_io.seek(0)
    # 创建一个Flask响应对象，将验证码图片的字节流作为响应体，设置响应的内容类型为'image/png'
    response = make_response(img_io.read())
    response.content_type = 'image/png'
    # 返回包含验证码图片的响应
    return response


# 注册
@bp.route('/register', methods=['POST', "GET"])
def register():
    if request.method == "POST":
        form = UserRegisterForm(data=request.form)
        if form.validate():
            # 保存到数据库
            # 将整数映射到BIGINT范围,为BIGINT的范围
            user = UserModel(user_id=int(uuid.uuid4().int) % 900000000 + 100000000, account=form.account.data,
                             password=hashPassword(form.password.data),
                             email=form.email.data)
            db.session.add(user)
            db.session.commit()
            # 将用户account存储在会话对象中
            session['account'] = form.account.data
            # 重定向到首页
            return redirect(url_for("business.views"))
        else:
            # 获取所以错误内容，并储存到flask中，然后在模板中把flask信息展示出来
            for errors in form.errors.values():
                for error in errors:
                    flash(error)
            return render_template("register.html", form=form)
    else:
        form = UserRegisterForm()
        return render_template("register.html", form=form)


# 找回密码
@bp.route("/missPassword", methods=['POST', "GET"])
def missPassword():
    if request.method == "GET":
        form = UserMissPasswordForm()
        return render_template("missPassword.html", form=form)
    else:
        form = UserMissPasswordForm(data=request.form)
        if form.validate():
            account = form.account.data
            user = UserModel.query.filter_by(account=account).first()
            user.password = hashPassword(form.newPassword.data)
            # 同步到数据库
            db.session.commit()
            return redirect(url_for("business.login"))
        else:
            # 获取所以错误内容，并储存到flask中，然后在模板中把flask信息展示出来
            for errors in form.errors.values():
                for error in errors:
                    flash(error)
            return render_template("missPassword.html", form=form)


@bp.route("/missPassword/emailCode", methods=["POST"])
def getEmailCode():
    data = request.get_json()
    account = data['account']
    user = UserModel.query.filter_by(account=account).first()
    if user:
        # 随机字母和数字的组合
        code = "".join(random.choices((string.ascii_letters + string.digits), k=6))
        # Input/Output
        message = Message(subject="SparkML推荐系统项目_忘记密码_邮箱验证码", recipients=[user.email],
                          body=f"您的验证码是：{code}；请不要泄露给他人，否则后果自负。")
        mail.send(message)
        # 将生成的邮箱验证码字符串和当前时间戳保存到用户的会话(session)中
        session['emailCode'] = {'code': code, 'timestamp': time.time()}
        return jsonify({"status": "success", "message": "发送成功"})
    else:
        return jsonify({"status": "fail", "message": "用户账号无效！"})


# 退出登录
@bp.route("/logout", methods=['GET'])
def logout():
    # 删除会话里面的account
    session.pop("account")
    # 重定向到首页
    return redirect(url_for("business.views"))


# 商品详情
@bp.route("/detail/<int:product_id>", methods=['GET'])
def getDetail(product_id):
    # 查询数据库或其他数据源，获取商品详情
    product = ProductModel.query.filter_by(product_id=product_id).first()
    product = product.__dict__
    del product['_sa_instance_state']
    return render_template("detail.html", product=product)


# 对商品评分
@bp.route("/rating", methods=['POST'])
@login_required
def setRating():
    # 获取评分数据
    data = request.get_json()
    rating = float(data.get('rating'))
    product_id = data.get('product_id')
    # 查询对应的商品
    product = ProductModel.query.filter_by(product_id=product_id)
    if product is None:
        return jsonify({"status": "fail", "message": "Product not found"})
    # 创建评分对象
    ratings = RatingsModel(rating=rating, product_id=product_id, user_id=g.user.user_id,
                           rating_time=datetime.datetime.now())
    # 将评分数据存储到数据库
    db.session.add(ratings)
    db.session.commit()
    return jsonify({"status": "success"})


# 返回一个商品的平均评分
@bp.route("/average_rating/", methods=["POST"])
def getAverage():
    data = request.get_json()
    product_id = data.get("product_id")
    subquery = db.session.query(func.avg(RatingsModel.rating).label('average_rating')).filter(
        RatingsModel.product_id == product_id).subquery()
    average_rating_result = db.session.query(subquery.c.average_rating).first()[0]
    if average_rating_result:
        average_rating = round(average_rating_result, 1)  # 获取平均评分
        return jsonify({"average_rating": average_rating})

    return jsonify({"error": f"找不到商品"}), 404
